/**
 * $Author: francesco.benincasa $
 * $Date: 2007-02-20 16:51:30 +0100 (mar, 20 feb 2007) $
 * $Rev: 485 $
 */
package org.stars.database.connectionpool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDriver;
import org.apache.commons.logging.Log;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool.Config;
import org.stars.database.ConnectionPool;

/**
 * @author Francesco Benincasa (908099)
 * 
 */
public class DBCPConnectionPool extends ConnectionPoolBase implements ConnectionPool {

	/**
	 * Crea un connection pool gestito da DBCP.
	 * 
	 * @param sName
	 * @param connectURI
	 * @param username
	 * @param password
	 * @param driver
	 * @param maxActiveConnection
	 * @param testQuery
	 */
	public DBCPConnectionPool(String sName, String connectURI, String username, String password, String driver,
			Integer maxActiveConnection, String testQuery) {
		super();
		Log log = getLogger();
		try {
			name = sName.toUpperCase();
			maxActiveConnection = maxActiveConnection == null ? 5 : maxActiveConnection;
			testQuery = (testQuery == null || "".equalsIgnoreCase(testQuery.trim())) ? "select 1 from dual" : testQuery;
			driverName = (driver == null || "".equalsIgnoreCase(driver.trim())) ? "oracle.jdbc.driver.OracleDriver" : driver;
			setupDriver(name, connectURI, username, password, driverName, maxActiveConnection, testQuery);
			setInfo("Url: " + connectURI + " User:" + username);
			log.info("Create connection pool (DBCP) " + sName);
		} catch (Exception e) {
			log.fatal("It is impossible to create the connection pool "+sName+" "+e.toString());
		}
	}

	/**
	 * 
	 */
	private String driverName;

	/**
	 * 
	 */
	private String name;

	/**
	 * @param poolName
	 * @param connectURI
	 * @param username
	 * @param password
	 * @param driverName
	 * @param maxActiveConnection
	 * @param testQuery
	 * @throws Exception
	 */
	@SuppressWarnings("unused")
	public static void setupDriver(String poolName, String connectURI, String username, String password,
			String driverName, Integer maxActiveConnection, String testQuery) throws Exception {
		//
		// First, we'll need a ObjectPool that serves as the
		// actual pool of connections.
		//
		// We'll use a GenericObjectPool instance, although
		// any ObjectPool implementation will suffice.
		//
		Config config = new Config();

		config.maxActive = maxActiveConnection;
		config.testWhileIdle = false;
		config.testOnBorrow = true;
		config.testOnReturn = false;
		config.whenExhaustedAction = 2; // when exhausted action, 0 = fail, 1 =
										// block, 2 = grow

		ObjectPool connectionPool = new GenericObjectPool(null, config);

		//
		// Next, we'll create a ConnectionFactory that the
		// pool will use to create Connections.
		// We'll use the DriverManagerConnectionFactory,
		// using the connect string passed in the command line
		// arguments.
		//
		ConnectionFactory connectionFactory;
		if (username.length() > 0) {
			connectionFactory = new DriverManagerConnectionFactory(connectURI, username, password);
		} else {
			connectionFactory = new DriverManagerConnectionFactory(connectURI, new Properties());
		}

		//
		// Now we'll create the PoolableConnectionFactory, which wraps
		// the "real" Connections created by the ConnectionFactory with
		// the classes that implement the pooling functionality.
		//

		PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
				connectionPool, null, testQuery, false, true);

		//
		// Finally, we create the PoolingDriver itself...
		//
		Class.forName(driverName);
		Class.forName("org.apache.commons.dbcp.PoolingDriver");
		PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");

		//
		// ...and register our pool with it.
		//        
		poolName = poolName.toUpperCase(); // uppercase
		driver.registerPool(poolName, connectionPool);

		//
		// Now we can just use the connect string
		// "jdbc:apache:commons:dbcp:example"
		// to access our pool of Connections.
		//        
	}

	public void printDriverStats() throws Exception {
		PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
		ObjectPool connectionPool = driver.getConnectionPool(name);

		Log log = getLogger();
		log.info("NumActive: " + connectionPool.getNumActive());
		log.info("NumIdle: " + connectionPool.getNumIdle());
	}

	public void shutdownDriver() throws Exception {
		PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
		driver.closePool(name);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.insiel.database.ConnectionPool#getConnection()
	 */
	@Override
	public Connection getConnection() throws SQLException {
		return getConnection(DriverManager.getConnection("jdbc:apache:commons:dbcp:" + name));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.insiel.database.ConnectionPool#getName()
	 */
	@Override
	public String getName() {
		return name;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.insiel.database.ConnectionPool#setName(java.lang.String)
	 */
	@Override
	public void setName(String value) {
		name = name.toUpperCase();
		name = value;
	}

}
